package com.ideaaedi.zoo.diy.artifact.tenant.tenant;

import com.ideaaedi.zoo.commonbase.component.auth.AuthUrlWhitelist;
import com.ideaaedi.zoo.commonbase.util.ZooContext;
import com.ideaaedi.zoo.diy.artifact.tenant.properties.nested.VisitorTenantInfo;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.util.AntPathMatcher;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Objects;
import java.util.Optional;

/**
 * 添加游客用户id & 租户信息
 * <pre>
 * 添加的前提：
 * 1. 当前不存在用户登录态
 * 2. 用户请求的url是白名单中的url
 * </pre>
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img
 * src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 1.0.0
 */
public class VisitorTenantFilter implements Filter {
    
    protected final AntPathMatcher antPathMatcher = new AntPathMatcher();
    
    protected final AuthUrlWhitelist authUrlWhitelist;
    
    protected final VisitorTenantInfo visitorTenantInfo;
    
    public VisitorTenantFilter(@Nonnull VisitorTenantInfo visitorTenantInfo, @Nullable AuthUrlWhitelist authUrlWhitelist) {
        this.visitorTenantInfo = visitorTenantInfo;
        this.authUrlWhitelist = authUrlWhitelist;
    }
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
        // 如果登录态存在，则忽略
        Long currUserId = ZooContext.Auth.currUserId();
        if (currUserId != null) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        // 如果白名单为空，则忽略
        if (authUrlWhitelist == null) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        if (!(servletRequest instanceof HttpServletRequest httpServletRequest)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        String servletPath = Objects.requireNonNull(httpServletRequest).getServletPath();
        boolean isWhitelist = Optional.of(authUrlWhitelist)
                .map(AuthUrlWhitelist::whitelist)
                .map(x -> x.stream().anyMatch(url -> antPathMatcher.match(url, servletPath)))
                .orElse(false);
        // 如果白名单未命中，则忽略
        if (!isWhitelist) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        // 设置游客的 用户id和对应的租户信息
        settingVisitorTenantInfo(httpServletRequest, servletResponse, filterChain);
    }

    /**
     * 设置游客的 用户id和对应的租户信息
     * <pre>
     * 注：只有当请求没有登录态（即：没有有效的token） && 命中白名单时，才会走到此方法
     * </pre>
     */
    protected void settingVisitorTenantInfo(HttpServletRequest httpServletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try {
            ZooContext.Complex.setUserIdAndTenantScope(visitorTenantInfo);
            filterChain.doFilter(httpServletRequest, servletResponse);
        } finally {
            ZooContext.Complex.clear(visitorTenantInfo);
        }
    }
}
